﻿using Microsoft.AspNetCore.Http;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace FileManagerSystem.Middleware
{
    /// <summary>
    /// 功能描述：Api日志记录中间件
    /// </summary>
    public class ApiLogMiddleware
    {
        public readonly RequestDelegate _next;
        private SysRequestLogModel _sysRequestLogModel;
        /// <summary>
        /// Api日志记录中间件构造初始化参数
        /// </summary>
        /// <param name="next"></param>
        public ApiLogMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        /// <summary>
        /// 运行管道
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            _sysRequestLogModel = new SysRequestLogModel();
            HttpRequest request = context.Request;
            _sysRequestLogModel.Url = request.Path.Value;
            _sysRequestLogModel.Method = request.Method;
            _sysRequestLogModel.ExcuteStartTime = DateTime.Now;
            string requestBody = "";
            //获取请求参数
            if (request.Method.ToLower() == "post")
            {
                //post请求   todo: 此处可能有问题
                //request.EnableRewind(); //启用倒带功能，就可以让 Request.Body 可以再次读取
                //request.Body.Position = 0;
                //Stream stream = request.Body;
                //long byteLen = request.ContentLength ?? 0;
                //byte[] buffer = new byte[byteLen];
                //stream.Read(buffer, 0, buffer.Length);
                //requestBody = Encoding.UTF8.GetString(buffer);

                ////再将字节流位置重置为0
                //request.Body.Position = 0;

                if (context.Request.Body.CanRead)
                {
                    var memery = new MemoryStream();
                    context.Request.Body.CopyTo(memery);
                    memery.Position = 0;
                    requestBody = new StreamReader(memery, UTF8Encoding.UTF8).ReadToEnd();
                    memery.Position = 0;
                    context.Request.Body = memery;
                }
                if (requestBody.Contains("Content-Disposition: form-data;")&&requestBody.Contains("Content-Type: "))//如果form表单传的是文件，则
                {
                    requestBody = "";
                }
            }
            else
            {
                //get请求
                requestBody = request.QueryString.Value;
            }
            //请求入参赋值
            
            _sysRequestLogModel.RequestBody = requestBody;
            //请求入参时进行日志记录一次-应用监听到请求时进行一次记录
            //NLog.LogManager.GetLogger("ApiLogs").Info(_sysRequestLogModel.RequestLog());

            //获取Response.Body数据流
            var responseStream = context.Response.Body;
            using (var body = new MemoryStream())
            {
                context.Response.Body = body;
                //跳转下个中间件
                await _next(context);

                _sysRequestLogModel.ResponseBody = await FormatResponse(context.Response);

                await body.CopyToAsync(responseStream);
            }

            //请求进行响应时进行日志记录
            context.Response.OnCompleted(() =>
            {
                //响应完成后，进行一次日志记录
                _sysRequestLogModel.ExcuteEndTime = DateTime.Now;
                NLog.LogManager.GetLogger("ApiLogs").Info( _sysRequestLogModel.ResponseLog());
                return Task.CompletedTask;
            });
        }

        /// <summary>
        /// 返回响应内容字符串
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        private async Task<string> FormatResponse(HttpResponse response)
        {
            response.Body.Seek(0, SeekOrigin.Begin);
            string text = await new StreamReader(response.Body).ReadToEndAsync();
            response.Body.Seek(0, SeekOrigin.Begin);
            return text;
        }
    }

    /// <summary>
    /// 功能描述:请求日志实体类
    /// </summary>
    public class SysRequestLogModel
    {
        /// <summary>
        /// 请求地址
        /// </summary>
        public string Url { get; set; }

        /// <summary>
        /// 请求方式
        /// GET/POST
        /// </summary>
        public string Method { get; set; }

        /// <summary>
        /// 请求体参数
        /// </summary>
        public string RequestBody { get; set; }

        /// <summary>
        /// 响应体参数
        /// </summary>
        public string ResponseBody { get; set; }

        /// <summary>
        /// 请求开始时间
        /// </summary>
        public DateTime? ExcuteStartTime { get; set; }

        /// <summary>
        /// 请求结束时间
        /// </summary>
        public DateTime? ExcuteEndTime { get; set; }

        /// <summary>
        /// 请求接受日志信息
        /// </summary>
        /// <returns></returns>
        public string RequestLog()
        {
            StringBuilder sb = new StringBuilder("0.api请求开始,具体信息如下:");
            sb.AppendFormat("请求地址:{0}", this.Url);
            sb.AppendFormat(";请求方式:{0}", this.Method);
            if (ExcuteStartTime.HasValue)
                sb.AppendFormat(";请求时间:{0}", this.ExcuteStartTime.Value.ToString("yyyy-MM-dd HH:mm:ss fff"));
            sb.AppendFormat(";请求参数:{0}", this.RequestBody);
            return sb.ToString();
        }

        /// <summary>
        /// 请求接受响应日志信息
        /// </summary>
        /// <returns></returns>
        public string ResponseLog()
        {
            StringBuilder sb = new StringBuilder("1.api请求响应,具体信息如下:");
            sb.AppendFormat("请求地址:{0}", this.Url);
            sb.AppendFormat(";请求方式:{0}", this.Method);
            if (this.ExcuteEndTime.HasValue)
            {
                sb.AppendFormat(";响应时间:{0}", (this.ExcuteEndTime.Value - this.ExcuteStartTime.Value).TotalSeconds);
                sb.AppendFormat(";返回结果:{0}", this.ResponseBody);
            }
            sb.AppendFormat(";请求时间:{0}", this.ExcuteStartTime.Value.ToString("yyyy-MM-dd HH:mm:ss fff"));
            sb.AppendFormat(";请求参数:{0}", this.RequestBody);
            return sb.ToString();
        }
    }
}
